package com.bert.controller;

import com.bert.entity.NodeEntity;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@RequestMapping("/zookeeper")
@RestController
public class ZookeeperController {

    private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final String CONNECT_STRING = "192.168.38.28:2181";
    private static final int SESSION_TIMEOUT = 5000;
    private static final int CONNECTION_TIMEOUT = 5000;
    private static final CuratorFramework client = CuratorFrameworkFactory.newClient(CONNECT_STRING, SESSION_TIMEOUT, CONNECTION_TIMEOUT, new ExponentialBackoffRetry(1000, 3));

    ZookeeperController (){
        client.start();
    }

    @GetMapping("/getAll")
    public List<NodeEntity> getAll(String path){
        return this.getTree(path);
    }

    private List<NodeEntity> getTree(String path) {
        List<NodeEntity> list = new ArrayList<>();
        try {
            List<String> childNode = client.getChildren().forPath(path);
            for (String node : childNode) {
                String childPath = path.equals("/") ? "/" + node : path + "/" + node;
                NodeEntity childEntity = this.getData(childPath);
                List<NodeEntity> tree = this.getTree(childPath);
                childEntity.setChild(tree);
                list.add(childEntity);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    @GetMapping("/getData")
    public NodeEntity getData(String path) {
        NodeEntity entity = new NodeEntity();
        try {
            // 查内容
            byte[] data = client.getData().forPath(path);
            // 查状态
            Stat stat = new Stat();
            client.getData().storingStatIn(stat).forPath(path);

            entity.setNodePath(path);
            entity.setData(new String(data));
            entity.setSize(data.length);
            entity.setVersion(stat.getVersion());
            entity.setModDate(this.timeToStr(stat.getMtime()));
            entity.setStat(stat.toString());
        } catch (Exception e) {
            entity.setNodePath(e.getMessage());
        }
        return entity;
    }

    @GetMapping("/create")
    public NodeEntity create(String nodePath, String data)  {
        String path = null;
        NodeEntity entity = new NodeEntity();
        try {
            path = client.create().creatingParentsIfNeeded().forPath(
                    nodePath, data.getBytes());
        } catch (Exception e) {
            entity.setNodePath(e.getMessage());
        }
        if (!Objects.isNull(path)) {
            entity = this.getData(nodePath);
        }
        return entity;
    }

    @GetMapping("/delete")
    public String deleteNode(String path) {
        // deletingChildrenIfNeeded如果有子节点一并删除
        // guaranteed必须成功比如网络抖动时造成命令失败
        String msg = "success";
        try {
            client.delete().guaranteed().deletingChildrenIfNeeded().inBackground(new BackgroundCallback() {
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                    System.out.println("删除成功");
                    // { "path":"/javacui/p1","resultCode":0,"type":"DELETE"}
                    System.out.println(curatorEvent);
                }
            }).forPath(path);
        } catch (Exception e) {
            msg = e.getMessage();
        }
        return msg;
    }

    private String timeToStr(Long time) {
        LocalDateTime dateTime = LocalDateTime.ofEpochSecond(time/1000L, 0, ZoneOffset.ofHours(8));
        return dateTime.format(formatter);
    }

}
